/*A program to model a Pendulum and plot Omega vs theta */
import java.awt.*;
import java.awt.event.*;

class Pendulum3 extends Canvas implements Runnable {
	double theta;
	boolean running = false;
	
	DoubleScroller driveScroll = new DoubleScroller("Drive Amplitude ",0,2,0.01,0.5);
	Button runButton = new Button("Start");
	Plot phasePlot = new Plot("Omega vs Theta",-Math.PI,Math.PI,Math.PI/4,-Math.PI,Math.PI,Math.PI/4);
	
	Pendulum3() {  //Constructor setups up goey
		setSize(400,400);
		Frame pictureFrame = new Frame("Driven, Damped Pendulum");
		Panel canvasPanel = new Panel();
		Panel controlPanel = new Panel();
		
		runButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				running = !running;
		}});
		
		controlPanel.add(runButton);
		pictureFrame.add(controlPanel,BorderLayout.SOUTH);
		canvasPanel.add(this);
		controlPanel.add(driveScroll);
		pictureFrame.add(canvasPanel);
		pictureFrame.pack();
		pictureFrame.setVisible(true);
		Thread myThread = new Thread(this);  
		myThread.start();
	}
	
	public void paint(Graphics g) {  //Sets up animation too draw pendulum
		int x2 = (int) Math.round(200 + 150*Math.sin(theta));
		int y2 = (int) Math.round(200 + 150*Math.cos(theta));
		g.setColor(Color.blue);
		g.drawLine(200,200,x2,y2);
		g.setColor(Color.magenta);
		g.fillOval(195,195,10,10);
		g.setColor(Color.green);
		g.fillOval(x2-10,y2-10,20,20);
	}
	
	public void run() {
		double alpha;
		double omega = 0;
		double t = 0;
		double alphaMid;
		double thetaMid;
		double omegaMid;
		double dt = 0.002;
		double plotTheta;

		while (true) {
			if (running) {
				runButton.setLabel("Stop");
				for (int i=0;i< 0.1/dt;i++) {  //Euler-Richardson Algorithm
								
					alpha = torque(theta,omega,t);
					thetaMid = theta + omega * 0.5 * dt;
					omegaMid = omega + alpha * 0.5 * dt;
					alphaMid = torque(thetaMid,omegaMid,t + dt/2);
					theta += omegaMid * dt;
					omega += alphaMid * dt;
					t += dt;
					if (theta > Math.PI) {
						theta -= 2*Math.PI;
					}
					if (theta < -Math.PI ) {
						theta += 2*Math.PI;
					}
					phasePlot.setPointSize(1);
					phasePlot.setPointShape(Plot.SQUARE);
					phasePlot.addPoint(theta,omega);
				}		
			}
			if(!running) {
				runButton.setLabel("Start");
			}

			repaint();
			try {Thread.sleep(30);} catch (InterruptedException e) {}
		}

	}
	
	double torque(double theta, double omega, double t) { //pendulum acceleration
		double driveFreq = 2.0/3.0;
		double damp = 0.5;
		double driveAmp = driveScroll.getValue();
		return -Math.sin(theta) -damp*omega + driveAmp*Math.sin(driveFreq*t);
	}
	
	public static void main(String[] args) {
		new Pendulum3();
	}
}
		